package com.miao.im.server.session;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import com.miao.im.common.Message;
import com.miao.im.model.AuthResponseModel;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Auther: miaoguoxin
 * @Date: 2021/2/25 14:35
 * @Description:
 */
public class SessionManager {
    private static final AtomicInteger onlineNum = new AtomicInteger();

    private static final Map<Channel, SessionContext> CHANNEL_MAP = new ConcurrentHashMap<>();

    private static final Map<String, SessionContext> DEVICE_MAP = new ConcurrentHashMap<>();

    private static final Map<String, Set<SessionContext>> USER_MAP = new ConcurrentHashMap<>();

    private static final Map<String, Set<SessionContext>> GROUP_MAP = new ConcurrentHashMap<>();


    /**
     * 客户端连接后初始化注册
     * @author miaoguoxin
     * @date 2021/2/25
     */
    public static void bindConnect(SessionContext sessionContext) {
        CHANNEL_MAP.putIfAbsent(sessionContext.getChannel(), sessionContext);
        onlineNum.incrementAndGet();
    }

    /**
     * 连接断开操作
     * @author miaoguoxin
     * @date 2021/3/1
     */
    public static void unbindConnect(SessionContext sessionContext) {
        CHANNEL_MAP.remove(sessionContext.getChannel());
        onlineNum.decrementAndGet();
    }

    public static int getOnlineUserNum(){
        return onlineNum.get();
    }

    public static SessionContext get(Channel channel) {
        return CHANNEL_MAP.get(channel);
    }

    /**
     * 通过用户id获取
     * @author miaoguoxin
     * @date 2021/3/15
     */
    public static Set<SessionContext> getByUserId(String userId) {
        return USER_MAP.getOrDefault(userId, new ConcurrentHashSet<>());
    }

    /**
     * @Description: 通过设备号获取`
     * @Author: miaoguoxin
     * @Date: 2021/4/24
     */
    public static Optional<SessionContext> getByDeviceNumber(String deviceNumber) {
        return Optional.ofNullable(DEVICE_MAP.get(deviceNumber));
    }

    public static List<SessionContext> getAll() {
        return new ArrayList<>(CHANNEL_MAP.values());
    }

    /**
     * 登陆后绑定用户信息
     * @author miaoguoxin
     * @date 2021/3/12
     */
    public static void bindLoginInfo(AuthResponseModel.AuthResponse user, String sessionId, SessionContext sessionContext) {
        if (user == null || sessionContext == null) {
            return;
        }
        sessionContext.setUserInfo(user);
        sessionContext.setSessionId(sessionId);

        String userId = String.valueOf(user.getUserId());
        Set<SessionContext> sessionContexts = USER_MAP.get(userId);
        if (CollectionUtil.isEmpty(sessionContexts)) {
            sessionContexts = new ConcurrentHashSet<>();
            sessionContexts.add(sessionContext);
            USER_MAP.put(userId, sessionContexts);
        } else {
            sessionContexts.add(sessionContext);
        }

        DEVICE_MAP.put(user.getDeviceNumber(), sessionContext);
    }

    /**
     * @Description: 解绑登陆信息
     * @Author: miaoguoxin
     * @Date: 2021/3/20
     */
    public static void unbindLoginInfo(SessionContext sessionContext) {
        if (!sessionContext.isAuth()) {
            return;
        }
        AuthResponseModel.AuthResponse socketUser = sessionContext.getUserInfo();
        String userId = String.valueOf(socketUser.getUserId());
        unbindUser(userId, sessionContext);
        DEVICE_MAP.remove(socketUser.getDeviceNumber());
    }

    /**
     * @Description: 解绑 用户组
     * @Author: miaoguoxin
     * @Date: 2021/4/24
     */
    public static void unbindUser(String userId, SessionContext sessionContext) {
        Set<SessionContext> sessionContexts = USER_MAP.get(userId);
        if (CollectionUtil.isEmpty(sessionContexts)) {
            USER_MAP.remove(userId);
            return;
        }
        sessionContexts.remove(sessionContext);
        if (CollectionUtil.isEmpty(sessionContexts)) {
            USER_MAP.remove(userId);
        }
    }

    /**
     * 加入群聊
     * @author miaoguoxin
     * @date 2021/2/25
     */
    public static void bindGroup(String groupId, SessionContext sessionContext) {
        sessionContext.addGroup(groupId);
        Set<SessionContext> contexts = GROUP_MAP.get(groupId);
        if (CollectionUtil.isEmpty(contexts)) {
            contexts = new ConcurrentHashSet<>();
            GROUP_MAP.putIfAbsent(groupId, contexts);
        }
        contexts.add(sessionContext);
    }

    /**
     * 退出群聊
     * @author miaoguoxin
     * @date 2021/2/26
     */
    public static void unBindGroup(String groupId, SessionContext sessionContext) {
        sessionContext.removeGroup(groupId);
        Set<SessionContext> contexts = GROUP_MAP.get(groupId);
        if (CollectionUtil.isEmpty(contexts)) {
            GROUP_MAP.remove(groupId);
            return;
        }
        contexts.remove(sessionContext);
        if (CollectionUtil.isEmpty(contexts)) {
            GROUP_MAP.remove(groupId);
        }
    }

    /**
     * 解除所有群聊
     * @author miaoguoxin
     * @date 2021/2/26
     */
    public static void unBindAllGroup(SessionContext sessionContext) {
        for (String groupId : sessionContext.getGroupIds()) {
            unBindGroup(groupId, sessionContext);
        }
    }

    /**
     * 发送消息给指定用户
     * @author miaoguoxin
     * @date 2021/3/15
     */
    public static void sendToUser(String userId, Message message) {
        sendToUser(userId, message, null);
    }

    public static void sendToUser(String userId, Message message, GenericFutureListener<Future<? super Void>> listener) {
        Set<SessionContext> sessionContexts = USER_MAP.get(userId);
        if (CollectionUtil.isEmpty(sessionContexts)) {
            return;
        }
        for (SessionContext sessionContext : sessionContexts) {
            send(sessionContext, message, listener);
        }
    }

    /**
     * @Description: 发送到指定设备
     * @Author: miaoguoxin
     * @Date: 2021/4/24
     */
    public static void sendToDevice(String deviceNumber, Message message) {
        sendToDevice(deviceNumber, message, null);
    }

    public static void sendToDevice(String deviceNumber, Message message, GenericFutureListener<Future<? super Void>> listener) {
        SessionContext sessionContext = DEVICE_MAP.get(deviceNumber);
        if (sessionContext == null) {
            return;
        }
        send(sessionContext, message, listener);
    }

    /**
     * 发送消息
     * @author miaoguoxin
     * @date 2021/3/11
     */
    public static void send(SessionContext sessionContext, Message message) {
        send(sessionContext, message, null);
    }

    public static void send(SessionContext sessionContext, Message message, GenericFutureListener<Future<? super Void>> listener) {
        ByteBuf byteBuf = message.getByteBuf();
        BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(byteBuf);
        ChannelFuture channelFuture = sessionContext.getChannel().writeAndFlush(binaryWebSocketFrame);
        Optional.ofNullable(listener).ifPresent(channelFuture::addListener);
    }

    /**
     * 移除连接
     * @author miaoguoxin
     * @date 2021/2/25
     */
    public static SessionContext unbind(Channel channel) {
        SessionContext sessionContext = CHANNEL_MAP.get(channel);
        if (sessionContext == null) {
            return null;
        }
        unbindConnect(sessionContext);
        unbindLoginInfo(sessionContext);
        unBindAllGroup(sessionContext);
        return sessionContext;
    }

}
